﻿using System;
using GammaJul.ReSharper.GammaXaml.Psi;
using GammaJul.ReSharper.GammaXaml.Psi.Xaml;
using JetBrains.Annotations;
using JetBrains.Application.Progress;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Feature.Services.Bulbs;
using JetBrains.ReSharper.Feature.Services.Xaml.Bulbs;
using JetBrains.ReSharper.Intentions.Extensibility;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.ReSharper.Psi.Xaml.Impl;
using JetBrains.ReSharper.Psi.Xaml.Tree;
using JetBrains.ReSharper.Psi.Xaml.Tree.MarkupExtensions;
using JetBrains.ReSharper.Psi.Xml.Parsing;
using JetBrains.ReSharper.Psi.Xml.Tree;
using JetBrains.TextControl;
using JetBrains.Util;

namespace GammaJul.ReSharper.GammaXaml.ContextActions.Xaml {

	/// <summary>
	/// A context action that transforms a XAML <c>{x:Static RelativeSource.X}</c> markup extension into a <c>{RelativeSource X}</c> one.
	/// </summary>
	[ContextAction(Name = "Transform x:Static to RelativeSource", Group = "XAML", Description = "Transforms a XAML x:Static RelativeSource into a RelativeSource one.")]
	public class XStaticToRelativeSourceAction : ContextActionBase {
		private readonly XamlContextActionDataProvider _provider;

		[NotNull]
		private static string GetRelativeSourceMarkupString(RelativeSourceMode mode) {
			return "{RelativeSource " + mode.ToKeyword() + "}";
		}

		[NotNull]
		private static string GetRelativeSourceTagString(RelativeSourceMode mode) {
			return "<RelativeSource Mode=\"" + mode.ToKeyword() + "\"/>";
		}

		public override string Text {
			get {
				var xStatic = _provider.FindNodeAtCaret<IXStatic>();
				Assertion.AssertNotNull(xStatic, "relSource != null");
				var mode = xStatic.GetRelativeSourceMode();
				string xStaticString = xStatic is IMarkup ? GetRelativeSourceMarkupString(mode) : GetRelativeSourceTagString(mode);
				return "Use '" + xStaticString + "'";
			}
		}

		protected override Action<ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress) {
			var xStatic = _provider.FindNodeAtCaret<IXStatic>();
			if (xStatic == null)
				return null;

			RelativeSourceMode mode = xStatic.GetRelativeSourceMode();
			XamlElementFactory elementFactory = XamlElementFactory.GetElementFactory(xStatic);

			ITreeNode relSourceNode;
			if (xStatic is IMarkup)
				relSourceNode = elementFactory.CreateMarkup(GetRelativeSourceMarkupString(mode));
			else if (xStatic is IXmlTag)
				relSourceNode = elementFactory.CreateTag(GetRelativeSourceTagString(mode), xStatic.GetPsiServices(), xStatic.GetPsiModule(), true);
			else
				relSourceNode = null;

			if (relSourceNode != null)
				xStatic.ReplaceBy(relSourceNode);

			return null;
		}

		public override bool IsAvailable(IUserDataHolder cache) {
			return _provider.FindNodeAtCaret<IXStatic>().GetRelativeSourceMode() != RelativeSourceMode.UNKNOWN;
		}

		public XStaticToRelativeSourceAction([NotNull] XamlContextActionDataProvider provider) {
			if (provider == null)
				throw new ArgumentNullException("provider");
			_provider = provider;
		}
	}

}